package com.pw.canbuslogger.view.grid;

import java.util.Calendar;

import javax.swing.table.AbstractTableModel;

import com.pw.canbuslogger.CANBusRecordFields;
import com.tuamotu.commons.comparator.BeanComparatorUtil;
import com.tuamotu.commons.comparator.IBeanComparator;
import com.tuamotu.commons.comparator.IBeanComparator.Order;
import com.tuamotu.commons.comparator.IFieldComparatorMetadata;
import com.tuamotu.commons.dataset.Dataset;
import com.tuamotu.commons.dataset.DatasetIndex;
import com.tuamotu.commons.dataset.IBookmark;
import com.tuamotu.commons.field.ArrayBeanFieldImpl;
import com.tuamotu.commons.field.IField;

public class CANBusDatasetTableModel extends AbstractTableModel implements IResetFilterListener {

    private static final long serialVersionUID = -7641697638120796375L;

    private Dataset<Object[]> dataset;
    public final IField<Object[]> ID_FIELD;
    public final IField<Object[]> LEN_FIELD;
    public final IField<Object[]> BYTE1_FIELD;
    public final IField<Object[]> BYTE2_FIELD;
    public final IField<Object[]> BYTE3_FIELD;
    public final IField<Object[]> BYTE4_FIELD;
    public final IField<Object[]> BYTE5_FIELD;
    public final IField<Object[]> BYTE6_FIELD;
    public final IField<Object[]> BYTE7_FIELD;
    public final IField<Object[]> BYTE8_FIELD;
    public final IField<Object[]> COUNT_FIELD;
    public final IField<Object[]> LAST_FIELD;
    public final IField<Object[]>[] fields;
    public final DatasetIndex<Object[]> datasetIndex;

    @SuppressWarnings("unchecked")
    public CANBusDatasetTableModel() {
        this.dataset = new Dataset<Object[]>();

        this.ID_FIELD = dataset.addField(new ArrayBeanFieldImpl<Object>(CANBusRecordFields.ID, "ID", true));
        this.LEN_FIELD = dataset.addField(new ArrayBeanFieldImpl<Object>(CANBusRecordFields.LEN, "Length", true));
        this.BYTE1_FIELD = dataset.addField(new ArrayBeanFieldImpl<Object>(CANBusRecordFields.BYTE01, "Byte-1", true));
        this.BYTE2_FIELD = dataset.addField(new ArrayBeanFieldImpl<Object>(CANBusRecordFields.BYTE02, "Byte-2", true));
        this.BYTE3_FIELD = dataset.addField(new ArrayBeanFieldImpl<Object>(CANBusRecordFields.BYTE03, "Byte-3", true));
        this.BYTE4_FIELD = dataset.addField(new ArrayBeanFieldImpl<Object>(CANBusRecordFields.BYTE04, "Byte-4", true));
        this.BYTE5_FIELD = dataset.addField(new ArrayBeanFieldImpl<Object>(CANBusRecordFields.BYTE05, "Byte-5", true));
        this.BYTE6_FIELD = dataset.addField(new ArrayBeanFieldImpl<Object>(CANBusRecordFields.BYTE06, "Byte-6", true));
        this.BYTE7_FIELD = dataset.addField(new ArrayBeanFieldImpl<Object>(CANBusRecordFields.BYTE07, "Byte-7", true));
        this.BYTE8_FIELD = dataset.addField(new ArrayBeanFieldImpl<Object>(CANBusRecordFields.BYTE08, "Byte-8", true));
        this.LAST_FIELD = dataset.addField(new ArrayBeanFieldImpl<Object>(CANBusRecordFields.TIME, "Last", true));
        this.COUNT_FIELD = dataset.addField("Count", Integer.class);

        IFieldComparatorMetadata<Object[]> idMetadata = new IFieldComparatorMetadata<Object[]>(ID_FIELD, Order.ASC, true);
        IFieldComparatorMetadata<Object[]> b1Metadata = new IFieldComparatorMetadata<Object[]>(BYTE1_FIELD, Order.ASC, true);
        IFieldComparatorMetadata<Object[]> b2Metadata = new IFieldComparatorMetadata<Object[]>(BYTE2_FIELD, Order.ASC, true);
        IFieldComparatorMetadata<Object[]> b3Metadata = new IFieldComparatorMetadata<Object[]>(BYTE3_FIELD, Order.ASC, true);

        IBeanComparator<Object[]> comparator = BeanComparatorUtil.getBeanComparator(idMetadata, b1Metadata, b2Metadata, b3Metadata);

        this.datasetIndex = this.dataset.addIndex(comparator);

        this.fields = new IField[] { ID_FIELD, LEN_FIELD, BYTE1_FIELD, BYTE2_FIELD, BYTE3_FIELD, BYTE4_FIELD, BYTE5_FIELD, BYTE6_FIELD, BYTE7_FIELD, BYTE8_FIELD, LAST_FIELD, COUNT_FIELD };

    }

    @Override
    public String getColumnName(int column) {
        return fields[column].getDescription();
    }

    public IField<Object[]>[] getFields() {
        return this.fields;
    }

    @Override
    public int getRowCount() {
        return this.dataset.getRecordCount();
    }

    @Override
    public int getColumnCount() {
        return this.fields.length;
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        IBookmark<Object[]> bkm = this.dataset.getBookmark(rowIndex, this.datasetIndex);
        return this.dataset.getValue(bkm, fields[columnIndex]);
    }

    @Override
    public void filterReset() {
        this.dataset.clear();
    }

    public void addRecord(Object[] toAdd) {
        IBookmark<Object[]> found = this.dataset.findFirst(toAdd, datasetIndex);
        if (found != null) {
            Integer count = dataset.getValue(found, COUNT_FIELD);
            count++;
            this.dataset.setValue(found, COUNT_FIELD, count);
            this.dataset.setValue(found, LAST_FIELD, toAdd[CANBusRecordFields.TIME]);
            int rowIndex = dataset.indexOf(found, datasetIndex);
            super.fireTableRowsUpdated(rowIndex, rowIndex);
        } else {
            IBookmark<Object[]> added = this.dataset.add(toAdd);
            this.dataset.setValue(added, COUNT_FIELD, 1);
            int rowIndex = this.dataset.indexOf(added, datasetIndex);
            super.fireTableRowsInserted(rowIndex, rowIndex);
        }
    }

    public long getAge(int row) {
        Calendar lastChange = this.dataset.getValue(row, LAST_FIELD, datasetIndex);
        long age = Calendar.getInstance().getTimeInMillis() - lastChange.getTimeInMillis();
        return age;
    }
    
    public Dataset<Object[]> getDataset() {
        return this.dataset;
    }

}
